#include "sk6812_spi.h"
#include <math.h>

// 灯条显存SPI数据缓存
uint8_t gWs2812bDat_SPI[WS2812B_AMOUNT * 24] = {0};
// 灯条显存
tWs2812bCache_TypeDef gWs2812bDat[WS2812B_AMOUNT] = {0};

// Rainbow wave效果的全局变量
static uint16_t wave_offset = 0;                       // 记录当前波浪的偏移量（用于控制波浪位置）。
static uint32_t last_update_time = 0;                  // 记录上一次更新波浪位置的时间（毫秒）。
static effect_mode_t current_effect = EFFECT_RED_WAVE; // 默认彩虹波浪

#define WAVE_SPEED 50  // 波浪移动速度(ms)
#define WAVE_LENGTH 24 // 波浪长度
#define DARK_LEDS 6    // 熄灭的LED数量

// 将指定LED的RGB颜色值转换为WS2812B协议要求的SPI数据格式，并存储到SPI发送缓冲区中。
void WS2812b_Set(uint16_t Ws2b812b_NUM, uint8_t r, uint8_t g, uint8_t b)
{
    uint8_t *pR = &gWs2812bDat_SPI[(Ws2b812b_NUM) * 24 + 8]; // 设置单个不同颜色分量的起始位置。Ws2b812b_NUM是第0颗。
    uint8_t *pG = &gWs2812bDat_SPI[(Ws2b812b_NUM) * 24];
    uint8_t *pB = &gWs2812bDat_SPI[(Ws2b812b_NUM) * 24 + 16];

    for (uint8_t i = 0; i < 8; i++)
    {
        if (g & 0x80)
        {
            *pG = CODE_1;
        }
        else
        {
            *pG = CODE_0;
        }
        if (r & 0x80)
        {
            *pR = CODE_1;
        }
        else
        {
            *pR = CODE_0;
        }
        if (b & 0x80)
        {
            *pB = CODE_1;
        }
        else
        {
            *pB = CODE_0;
        }
        r <<= 1;
        g <<= 1;
        b <<= 1;
        pR++;
        pG++;
        pB++;
    }
}
void WS2812B_Task(void)
{
    // 根据当前模式执行相应的灯效
    switch (current_effect)
    {
    case EFFECT_RAINBOW_WAVE:
        rainbow_wave_effect();
        break;
    case EFFECT_RED_GREEN_WAVE:
        red_green_wave_effect();
        break;
    case EFFECT_RED_WAVE:
        red_wave_effect();
        break;
        // default:
        //     rainbow_wave_effect();
        //     break;
    }

    // 将gWs2812bDat数据解析成SPI数据
    for (uint8_t iLED = 0; iLED < WS2812B_AMOUNT; iLED++)
    {
        WS2812b_Set(iLED, gWs2812bDat[iLED].R, gWs2812bDat[iLED].G, gWs2812bDat[iLED].B);
    }
    // 总线输出数据
    HAL_SPI_Transmit(&Spi1Handle, gWs2812bDat_SPI, sizeof(gWs2812bDat_SPI), 0XFFFF);
    uint8_t dat = 0;
    // 使总线输出低电平
    HAL_SPI_Transmit(&Spi1Handle, &dat, 1, 0XFFFF);
    // 帧信号：一个大于50us的低电平
    HAL_Delay(1);
}

// Red Wave纯红色波浪效果
void red_wave_effect(void)
{
    uint32_t current_time = HAL_GetTick();

    // 检查是否需要更新波浪位置
    if (current_time - last_update_time >= WAVE_SPEED)
    {
        wave_offset++;
        if (wave_offset >= WS2812B_AMOUNT)
        {
            wave_offset = 0;
        }
        last_update_time = current_time;
    }

    // 清空所有LED
    for (uint8_t i = 0; i < WS2812B_AMOUNT; i++)
    {
        gWs2812bDat[i].R = 0;
        gWs2812bDat[i].G = 0;
        gWs2812bDat[i].B = 0;
    }

    // 生成纯红色波浪效果 - 30颗灯珠，6个熄灭，24个亮着
    for (uint8_t i = 0; i < WS2812B_AMOUNT; i++)
    {
        // 在当前波浪位置下，第i颗灯珠相对于波浪起点的位置。
        int16_t relative_pos = (i - wave_offset + WS2812B_AMOUNT) % WS2812B_AMOUNT;

        // 波浪区域：24个亮灯，6个熄灭
        // 亮灯区域从位置3到位置26（24个LED）
        if (relative_pos >= 3 && relative_pos < 27)
        {
            // 计算在亮灯区域内的位置（0-23）
            uint8_t light_pos = relative_pos - 3;

            // 计算亮度，使用正弦波形，中间最亮
            float angle = (float)light_pos * 3.14159f / (WAVE_LENGTH - 1);
            float brightness_factor = sinf(angle);

            // 确保亮度在合理范围内
            if (brightness_factor < 0.1f)
                brightness_factor = 0.1f;

            // 设置纯红色
            gWs2812bDat[i].R = (uint8_t)(255 * brightness_factor);
            gWs2812bDat[i].G = 0;
            gWs2812bDat[i].B = 0;
        }
        // 其他6个位置保持黑色（熄灭状态）
    }
}
// Red Green Wave灯效函数
void red_green_wave_effect(void)
{
    uint32_t current_time = HAL_GetTick(); // 获取当前系统时间（毫秒）

    // 检查是否达到更新波浪的时间间隔
    if (current_time - last_update_time >= WAVE_SPEED)
    {
        wave_offset++; // 波浪偏移量+1（波浪向前移动）
        if (wave_offset >= WS2812B_AMOUNT)
        {
            wave_offset = 0; // 偏移量超过灯珠总数时重置（循环移动）
        }
        last_update_time = current_time; // 更新上次更新时间
    }

    // 清空所有LED
    for (uint8_t i = 0; i < WS2812B_AMOUNT; i++)
    {
        gWs2812bDat[i].R = 0;
        gWs2812bDat[i].G = 0;
        gWs2812bDat[i].B = 0;
    }

    // 生成红绿波浪效果 - 30颗灯珠：6个红色，6个过渡，18个绿色
    for (uint8_t i = 0; i < WS2812B_AMOUNT; i++)
    {
        // 在当前波浪位置下，第i颗灯珠相对于波浪起点的位置。
        int16_t relative_pos = (i - wave_offset + WS2812B_AMOUNT) % WS2812B_AMOUNT;
        // 当wave_offset增大时（波浪向前移动），这个差值会减小，相当于灯珠在波浪中的位置 "后退"，造成波浪向前流动的视觉效果。
        //+ WS2812B_AMOUNT：避免负数出现。 当i < wave_offset时，i - wave_offset会是负数，加上灯珠总数后确保结果为正数（不影响最终取模结果，但能避免负数取模的异常）。
        //% WS2812B_AMOUNT：将结果限制在 0 到WS2812B_AMOUNT-1的范围内，实现循环效果。
        if (relative_pos < 6) // 前6个LED：纯红色区域
        {
            // 亮度用正弦函数计算：0~π区间内，亮度从0.2升到1再降到0.2（模拟波浪起伏）
            float brightness = sinf((float)relative_pos * 3.14159f / 5.0f); // 除灯珠数量
            if (brightness < 0.2f)
                brightness = 0.2f; // 最低亮度限制（避免完全熄灭）
            // 纯红色（绿色和蓝色为0），亮度由brightness控制
            gWs2812bDat[i].R = (uint8_t)(255 * brightness);
            gWs2812bDat[i].G = 0;
            gWs2812bDat[i].B = 0;
        }
        else if (relative_pos < 12)
        {
            // 中间6个LED：红色到绿色的过渡区域
            uint8_t transition_pos = relative_pos - 6;
            float brightness = sinf((float)transition_pos * 3.14159f / 5.0f); // 除灯珠数量
            if (brightness < 0.2f)
                brightness = 0.2f;
            // 计算逻辑：将 transition_pos（0~5）转换为 0~1 之间的浮点数。作为红、绿两种颜色的 "权重"，
            float transition_factor = (float)transition_pos / 5.0f;
            // 红色分量 = 最大亮度 × (1 - 过渡系数) × 波浪亮度
            gWs2812bDat[i].R = (uint8_t)(255 * (1.0f - transition_factor) * brightness); // 红色占比随系数增大而减小，绿色占比随系数增大而增大。
            // 绿色分量 = 最大亮度 × 过渡系数 × 波浪亮度
            gWs2812bDat[i].G = (uint8_t)(255 * transition_factor * brightness);
            gWs2812bDat[i].B = 0;
        }
        else if (relative_pos < 30) // relative_pos范围：12~29（共18颗）
        {
            // 后18个LED：纯绿色区域
            uint8_t green_pos = relative_pos - 12; // 转换为0~17的局部位置
            // 亮度用正弦函数计算：0~π区间内，亮度从0.2升到1再降到0.2
            float brightness = sinf((float)green_pos * 3.14159f / 17.0f); // 除灯珠数量
            if (brightness < 0.2f)
                brightness = 0.2f; // 最低亮度限制（避免完全熄灭）

            // 纯红色（绿色和蓝色为0），亮度由brightness控制
            gWs2812bDat[i].R = 0;
            gWs2812bDat[i].G = (uint8_t)(255 * brightness);
            gWs2812bDat[i].B = 0;
        }
        // 其他位置保持黑色（熄灭状态）
    }
}
/*彩虹效果依赖 HSV 到 RGB 的转换，简单解释该函数的核心逻辑：
HSV 通过 “色相划分 6 个区域” 实现颜色转换，每个区域对应一种主色和相邻色的混合：
hue 0~60°：红色为主，绿色逐渐增加（红→橙→黄）；
hue 60~120°：绿色为主，红色逐渐减少（黄→绿）；
... 以此类推，覆盖 6 个区域后回到红色，形成循环。
函数中通过 fmodf(h/60, 2)-1 计算颜色混合比例，最终得到 RGB 分量。*/
// HSV转RGB函数
void hsv_to_rgb(float h, float s, float v, uint8_t *r, uint8_t *g, uint8_t *b)
{
    float c = v * s;
    float x = c * (1 - fabsf(fmodf(h / 60.0f, 2) - 1));
    float m = v - c;

    float r_temp, g_temp, b_temp;

    if (h >= 0 && h < 60)
    {
        r_temp = c;
        g_temp = x;
        b_temp = 0;
    }
    else if (h >= 60 && h < 120)
    {
        r_temp = x;
        g_temp = c;
        b_temp = 0;
    }
    else if (h >= 120 && h < 180)
    {
        r_temp = 0;
        g_temp = c;
        b_temp = x;
    }
    else if (h >= 180 && h < 240)
    {
        r_temp = 0;
        g_temp = x;
        b_temp = c;
    }
    else if (h >= 240 && h < 300)
    {
        r_temp = x;
        g_temp = 0;
        b_temp = c;
    }
    else
    {
        r_temp = c;
        g_temp = 0;
        b_temp = x;
    }

    *r = (uint8_t)((r_temp + m) * 255);
    *g = (uint8_t)((g_temp + m) * 255);
    *b = (uint8_t)((b_temp + m) * 255);
}

// Rainbow wave灯效函数
void rainbow_wave_effect(void)
{
    uint32_t current_time = HAL_GetTick();

    // 检查是否需要更新波浪位置
    if (current_time - last_update_time >= WAVE_SPEED)
    {
        wave_offset++;
        if (wave_offset >= WS2812B_AMOUNT)
        {
            wave_offset = 0;
        }
        last_update_time = current_time;
    }

    // 清空所有LED
    for (uint8_t i = 0; i < WS2812B_AMOUNT; i++)
    {
        gWs2812bDat[i].R = 0;
        gWs2812bDat[i].G = 0;
        gWs2812bDat[i].B = 0;
    }

    // 生成彩虹波浪效果 - 30颗灯珠，6个熄灭，24个亮着
    for (uint8_t i = 0; i < WS2812B_AMOUNT; i++)
    {
        // 在当前波浪位置下，第i颗灯珠相对于波浪起点的位置。
        int16_t relative_pos = (i - wave_offset + WS2812B_AMOUNT) % WS2812B_AMOUNT;
        // 当wave_offset增大时（波浪向前移动），这个差值会减小，相当于灯珠在波浪中的位置 "后退"，造成波浪向前流动的视觉效果。
        //+ WS2812B_AMOUNT：避免负数出现。 当i < wave_offset时，i - wave_offset会是负数，加上灯珠总数后确保结果为正数（不影响最终取模结果，但能避免负数取模的异常）。
        //% WS2812B_AMOUNT：将结果限制在 0 到WS2812B_AMOUNT-1的范围内，实现循环效果。

        // 亮灯区域：relative_pos在3~27之间（共24颗灯珠），其余6颗熄灭
        if (relative_pos >= 3 && relative_pos < 27)
        {
            // 计算在亮灯区域内的位置（0-23）
            uint8_t light_pos = relative_pos - 3;

            // 计算亮度，使用正弦波形，中间最亮
            float angle = (float)light_pos * 3.14159f / (WAVE_LENGTH - 1);
            float brightness_factor = sinf(angle);

            // 确保亮度在合理范围内
            if (brightness_factor < 0.1f)
                brightness_factor = 0.1f;

            // 彩虹的核心是 “颜色随位置渐变” ,计算彩虹色相，根据位置在波浪中的相对位置
            /*HSV 模型中，色相用 0~360 度表示颜色种类（0°= 红、60°= 黄、120°= 绿、180°= 青、240°= 蓝、300°= 紫、360°= 红）。
这里 light_pos 从 0 到 23 时，hue 从 0° 线性增加到 360°，覆盖完整的彩虹色范围，实现 “红→橙→黄→…→紫” 的渐变。*/
            float hue = (float)light_pos * 360.0f / (WAVE_LENGTH - 1);
            float saturation = 1.0f;         // 饱和度最大
            float value = brightness_factor; // 亮度根据波浪形状变化

            // 转换HSV到RGB
            uint8_t r, g, b;
            /*将 HSV 颜色模型的三个参数（色相、饱和度、明度）转换为 LED 实际需要的 RGB 值（红、绿、蓝分量）。 */
            hsv_to_rgb(hue, saturation, value, &r, &g, &b);

            // 设置彩虹色
            gWs2812bDat[i].R = r;
            gWs2812bDat[i].G = g;
            gWs2812bDat[i].B = b;
        }
        // 其他6个位置保持黑色（熄灭状态）
    }
}

// 切换到下一个灯效模式
void switch_to_next_effect(void)
{
    if (current_effect == EFFECT_RED_WAVE)
    {
        current_effect = EFFECT_RED_GREEN_WAVE;
    }
    else if (current_effect == EFFECT_RED_GREEN_WAVE)
    {
        current_effect = EFFECT_RAINBOW_WAVE;
    }
    else if (current_effect == EFFECT_RAINBOW_WAVE)
    {
        current_effect = EFFECT_RED_WAVE;
    }
    // else
    // {
    //     current_effect = EFFECT_RAINBOW_WAVE;
    // }
    last_update_time = HAL_GetTick();
}
